package com.kaluli.system.repository;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;

import com.kaluli.system.utils.AssertionConcern;
import com.kaluli.system.utils.DefaultPage;
import com.kaluli.system.utils.Pageable;


/**
 * 查询帮助对象
 * @author Louis Huang
 * @since 1.0
 */
public class QueryTerm extends AssertionConcern {
	
	private final Logger logger = Logger.getLogger(QueryTerm.class);
	
	public enum QueryType {
		QUERY , ROW , PAGE ;
	}
	
	private String hql ;
	private Map<String, Object> mapParams ;
	private Object[] arrParams ;
	private Integer number ;
	private Integer limit;
	private boolean uniqued;
	private boolean originHql ;			//是否为原始hql
	private QueryType type ;
	
	
	private QueryTerm(String hql, Map<String, Object> mapParams,
			Object[] arrParams, Integer number, Integer limit , boolean uniqued ) {
		this.hql = hql;
		this.mapParams = mapParams;
		this.arrParams = arrParams;
		this.number = number;
		this.limit = limit;
		this.uniqued = uniqued ;
		this.type = QueryType.QUERY;
		this.originHql = false;
	}
	
	public QueryTerm(String hql) {
		this( hql  , null , null , null , null , false);
	}

	public QueryTerm(String hql, Map<String, Object> mapParams) {
		this( hql  , mapParams , null , null , null , false);
	}

	public QueryTerm(String hql, Object[] arrParams) {
		this( hql  , null , arrParams , null , null , false);
	}
	
	public QueryTerm params(Map<String, Object> mapParams) {
		if( mapParams != null ) {
			this.mapParams = mapParams;
			this.arrParams = null;
		}
		return this;
	}
	
	public QueryTerm params(Object[] arrParams) {
		if( arrParams != null ) {
			this.mapParams = null;
			this.arrParams = arrParams;
		}
		return this;
	}
	
	public QueryTerm type(QueryType type) {
		this.type = type;
		return this;
	}
	
	/**
	 * 原始 hql  主要是针对计算多个 总条数有效
	 * @param origin
	 * @return
	 */
	public QueryTerm originHql(boolean origin) {
		this.originHql = origin;
		return this;
	}
	
	public QueryTerm number(Integer number) {
		this.number = number;
		return this;
	}
	
	public QueryTerm limit(Integer limit) {
		this.limit = limit;
		return this;
	}
	
	/**
	 * 查询列表是  是否为单个 还是多个 .
	 * @param uniqued
	 * @return
	 */
	public QueryTerm uniqued(boolean uniqued) {
		this.uniqued = uniqued;
		return this;
	}
	
	public <T> T query(Session session){
		assertArgumentNotEmpty(hql, " HQL 不能为空..");
		Query query = session.createQuery(hql);
		
		logger.debug(hql);
		
		if( mapParams != null ) {
			for(java.util.Map.Entry<String, Object> entry :  mapParams.entrySet()) {
				if( entry.getValue() instanceof Collection ) {
					Collection values = ( Collection ) entry.getValue();
					query.setParameterList(entry.getKey() , values);
				} else {
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
		}
		if( arrParams != null ) {
			for( int i = 0 ; i < arrParams.length ; i++ ) {
				query.setParameter(i, arrParams[i]);
			}
		}
		if( number != null && limit != null ) {
			query.setFirstResult(number * limit);
			query.setMaxResults(limit);
		}
		return uniqued ? (T) query.uniqueResult() : (T) query.list();
	}
	
	
	public  Long rowsCount(Session session){
		assertArgumentNotEmpty(hql, " HQL 不能为空..");
		
		String rowHql = hql.trim() ;
		
		if( !originHql ) {
			
			if( rowHql.toUpperCase().startsWith("SELECT") ) {
				
				String fromHql = rowHql.substring( rowHql.toUpperCase().indexOf("FROM") );
				
				String object = rowHql.substring(rowHql.toUpperCase().indexOf("SELECT") + 6 ,  rowHql.toUpperCase().indexOf("FROM") );
				
				rowHql = "SELECT COUNT(" + object + ") " + fromHql;
				
			} else {
				rowHql = "SELECT COUNT(*) " + rowHql;
			}
		}
		
		logger.debug(rowHql);
		
		Query query = session.createQuery( rowHql );
		if( mapParams != null ) {
			for(java.util.Map.Entry<String, Object> entry :  mapParams.entrySet()) {
				if( entry.getValue() instanceof Collection ) {
					Collection values = ( Collection ) entry.getValue();
					query.setParameterList(entry.getKey() , values);
				} else {
					query.setParameter(entry.getKey(), entry.getValue());
				}
			}
		}
		if( arrParams != null ) {
			for( int i = 0 ; i < arrParams.length ; i++ ) {
				query.setParameter(i, arrParams[i]);
			}
		}
		return (Long) query.uniqueResult();
	}
	
	public <T> Pageable<T> pageable( Session session){
		this.uniqued = false;
		List<T> results =  this.query(session);
		Long total = this.rowsCount(session);
		return new DefaultPage<T>(results, total , number , limit);
	}

	public QueryType getType() {
		return type;
	}

}
